package appImpl

import (
	"context"
	"encoding/json"
	"fmt"
	"strings"
	"time"

	"calculator/internal/app"
	"calculator/internal/core/incremental"
	"calculator/internal/core/schema"

	"github.com/pkg/errors"

	"gorm.io/driver/sqlite"
	"gorm.io/gorm"
	"gorm.io/gorm/logger"
)

// AppServiceImpl 数据访问对象
type AppServiceImpl struct {
	db            *gorm.DB                    // 数据库连接实例
	computer      *incremental.Computer       // 增量计算器
	changeHandler *incremental.ChangeHandler  // 增量计算处理器
	processor     *incremental.BatchProcessor // 批量处理器
	schema        *schema.Schema              // 数据模型
}

// NewAppService 创建新的DataServiceImpl实例
func NewAppService(db *gorm.DB, jsonContent []byte) (app.AppService, error) {

	// 初始化增量计算器和变更处理器
	computer := incremental.NewComputer(db)

	processor := incremental.NewBatchProcessor(db, computer)

	changeHandler := incremental.NewChangeHandler(db, computer, processor)

	app := AppServiceImpl{db: db, computer: computer, changeHandler: changeHandler, processor: processor}

	// 初始化Schema
	if err := app.UpdateSchema(jsonContent); err != nil {
		return nil, err
	}

	if err := app.Validate(); err != nil {
		return nil, err
	}

	return &app, nil
}

// CreateDB 根据Schema创建或更新数据库表结构
func CreateDB(config app.DBConfig, jsonContent []byte) (*gorm.DB, error) {
	// 根据驱动类型选择数据库连接
	var dialector gorm.Dialector
	switch config.Driver {
	case "sqlite":
		dialector = sqlite.Open(config.DSN)
	default:
		return nil, errors.Errorf("DataServiceImpl001: 不支持的数据库驱动: %s", config.Driver)
	}

	// 配置日志级别
	logLevel := logger.Silent
	if config.LogLevel >= 1 {
		logLevel = logger.Info
	}
	if config.LogLevel >= 2 {
		logLevel = logger.Warn
	}
	if config.LogLevel >= 3 {
		logLevel = logger.Error
	}

	// 连接数据库
	db, err := gorm.Open(dialector, &gorm.Config{
		Logger: logger.Default.LogMode(logLevel),
	})
	if err != nil {
		return nil, errors.Wrapf(err, "DataServiceImpl002: 连接数据库失败, dsn: %s", config.DSN)
	}

	// 获取底层sql.DB并设置连接池
	sqlDB, err := db.DB()
	if err != nil {
		return nil, errors.Wrapf(err, "DataServiceImpl003: 获取数据库连接池失败")
	}
	sqlDB.SetMaxIdleConns(10)           // 设置最大空闲连接数
	sqlDB.SetMaxOpenConns(100)          // 设置最大打开连接数
	sqlDB.SetConnMaxLifetime(time.Hour) // 设置连接最大复用时间

	var updatedSchema schema.Schema
	if err := json.Unmarshal(jsonContent, &updatedSchema); err != nil {
		return nil, errors.Wrapf(err, "SCHEMA015: JSON解析失败")
	}

	if err := updatedSchema.Validate(); err != nil {
		return nil, errors.Wrapf(err, "DATA018: 模型验证失败")
	}

	for _, table := range updatedSchema.Tables {
		dst, err := schema.ConvertTableToDst(table)
		if err != nil {
			return nil, errors.Wrapf(err, "DATA012: 转换表 %s 失败", table.Name)
		}

		// 显式指定表名以匹配schema定义
		if err := db.Table(table.Name).AutoMigrate(dst); err != nil {
			return nil, errors.Wrapf(err, "DATA013: 创建或更新表 %s 失败", table.Name)
		}
	}

	return db, nil
}

// GetDB 获取数据库连接
func (app *AppServiceImpl) GetDB(ctx context.Context) *gorm.DB {
	return app.db.WithContext(ctx)
}

// GetSchema 获取数据模型
func (app *AppServiceImpl) GetSchema() *schema.Schema {
	return app.schema
}

// UpdateSchema 更新整个Schema定义
func (app *AppServiceImpl) UpdateSchema(jsonContent []byte) error {

	var updatedSchema schema.Schema
	if err := json.Unmarshal(jsonContent, &updatedSchema); err != nil {
		return errors.Wrapf(err, "SCHEMA015: JSON解析失败")
	}

	// 验证更新后的Schema
	if err := updatedSchema.Validate(); err != nil {
		return errors.Wrapf(err, "SCHEMA016: 模型验证失败")
	}

	app.schema = &updatedSchema

	app.computer.UpdateSchema(app.schema)

	return nil
}

// ExportSchema 将Schema导出为JSON格式
func (app *AppServiceImpl) ExportSchema() ([]byte, error) {
	if app.schema == nil {
		return nil, errors.Errorf("SCHEMA013: Schema未加载")
	}

	jsonData, err := json.MarshalIndent(app.schema, "", "  ")
	if err != nil {
		return nil, errors.Wrapf(err, "SCHEMA014: Schema序列化失败")
	}

	return jsonData, nil
}

// GetTable 获取指定模型下的表
func (app *AppServiceImpl) GetTable(tableName string) (*schema.Table, error) {
	for _, table := range app.schema.Tables {
		if table.Name == tableName {
			return &table, nil
		}
	}

	return nil, errors.Errorf("SCHEMA005: 表不存在: %s", tableName)
}

// GetField 获取指定表中的字段
func (app *AppServiceImpl) GetField(tableName, fieldName string) (*schema.Field, error) {
	table, err := app.GetTable(tableName)
	if err != nil {
		return nil, err
	}

	for _, field := range table.Fields {
		if field.Name == fieldName {
			return &field, nil
		}
	}

	return nil, errors.Errorf("SCHEMA006: 字段不存在: %s.%s", tableName, fieldName)
}

// Validate 验证数据是否符合Schema定义
func (app *AppServiceImpl) Validate() error {
	// 检查Schema是否已加载
	if app.schema == nil {
		return errors.Errorf("SCHEMA019: Schema未加载")
	}

	// 检查Schema本身是否有效
	if err := app.schema.Validate(); err != nil {
		return errors.Wrapf(err, "SCHEMA008: 模型数据解析失败")
	}

	// 验证数据库表结构与Schema一致性
	for _, table := range app.schema.Tables {
		// 1. 验证表是否存在
		if err := app.validateTableExists(table.Name); err != nil {
			return err
		}

		// 2. 验证所有字段存在且属性匹配
		for _, field := range table.Fields {
			if err := app.validateField(table.Name, &field); err != nil {
				return err
			}
			// 验证索引
			if field.Index {
				hasIdx, err := app.hasIndex(table.Name, field.Name)
				if err != nil {
					return errors.Wrapf(err, "SCHEMA020: 查询索引失败 for %s.%s", table.Name, field.Name)
				}
				if !hasIdx {
					return errors.Errorf("SCHEMA020: 索引不存在: %s.%s", table.Name, field.Name)
				}
			}
		}
	}

	return nil
}

// validateTableExists 验证表是否存在于数据库中
func (app *AppServiceImpl) validateTableExists(tableName string) error {
	// SQLite特有的表存在性查询
	query := fmt.Sprintf("SELECT name FROM sqlite_master WHERE type='table' AND name='%s'", tableName)
	var dbTableName string
	if err := app.db.Raw(query).Scan(&dbTableName).Error; err != nil {
		return errors.Wrapf(err, "SCHEMA015: 查询表 %s 存在性失败", tableName)
	}
	if dbTableName == "" {
		return errors.Errorf("SCHEMA015: 表不存在: %s", tableName)
	}
	return nil
}

// validateField 验证字段存在且属性与Schema定义一致
func (app *AppServiceImpl) validateField(tableName string, field *schema.Field) error {
	// 查询字段信息
	query := fmt.Sprintf("PRAGMA table_info(%s)", tableName)
	rows, err := app.db.Raw(query).Rows()
	if err != nil {
		return errors.Wrapf(err, "SCHEMA016: 查询表 %s 字段信息失败", tableName)
	}
	defer rows.Close()

	found := false
	for rows.Next() {
		var col struct {
			Cid        int
			Name       string
			Type       string
			NotNull    int
			Dflt_value interface{}
			Pk         int
		}
		if err := rows.Scan(&col.Cid, &col.Name, &col.Type, &col.NotNull, &col.Dflt_value, &col.Pk); err != nil {
			return errors.Wrapf(err, "SCHEMA016: 扫描表 %s 字段信息失败", tableName)
		}

		if col.Name == field.Name {
			found = true
			// 验证字段类型
			actualType := strings.ToLower(col.Type)
			expectedType := strings.ToLower(string(field.Type))

			// 验证字段类型 - 修复类型映射验证
			typeMismatch := false
			switch field.Type {
			case schema.TypeArray, schema.TypeMap:
				// ARRAY 和 MAP 类型映射到 JSON
				if actualType != "json" {
					typeMismatch = true
				}
			case schema.TypeFloat:
				// FLOAT 类型可能映射为多种浮点数类型
				if !(strings.Contains(actualType, "float") || strings.Contains(actualType, "real") || strings.Contains(actualType, "decimal")) {
					typeMismatch = true
				}
			case schema.TypeVarchar:
				// VARCHAR 可能映射为 TEXT
				if !(actualType == "text" || strings.Contains(actualType, "varchar")) {
					typeMismatch = true
				}
			default:
				// 其他类型的基础检查
				if !strings.Contains(actualType, expectedType) {
					typeMismatch = true
				}
			}

			if typeMismatch {
				return errors.Errorf("SCHEMA017: 字段类型不匹配: %s.%s, 预期: %s, 实际: %s",
					tableName, field.Name, field.Type, col.Type)
			}

			// 验证是否可为空
			if (field.NotNull && col.NotNull == 0) || (!field.NotNull && col.NotNull == 1) {
				return errors.Errorf("SCHEMA018: 字段可空性不匹配: %s.%s, 预期: %v, 实际: %v",
					tableName, field.Name, field.NotNull, col.NotNull == 1)
			}

			// 验证主键
			if (field.Role == schema.RolePrimary && col.Pk == 0) || (field.Role != schema.RolePrimary && col.Pk == 1) {
				return errors.Errorf("SCHEMA019: 字段主键属性不匹配: %s.%s, 预期: %v, 实际: %v",
					tableName, field.Name, field.Role == schema.RolePrimary, col.Pk == 1)
			}

			break
		}
	}

	// 检查行迭代错误
	if err := rows.Err(); err != nil {
		return errors.Wrapf(err, "SCHEMA016: 遍历表 %s 字段信息失败", tableName)
	}

	if !found {
		return errors.Errorf("SCHEMA016: 字段不存在: %s.%s", tableName, field.Name)
	}

	return nil
}

// hasIndex 检查指定表的指定字段是否存在索引
func (app *AppServiceImpl) hasIndex(tableName, fieldName string) (bool, error) {
	// 获取表的所有索引
	var indexes []struct {
		Name string `gorm:"column:name"`
	}
	query := fmt.Sprintf("PRAGMA index_list(%s)", tableName)
	if err := app.db.Raw(query).Scan(&indexes).Error; err != nil {
		return false, err
	}

	// 检查每个索引是否包含目标字段
	for _, idx := range indexes {
		var columns []struct {
			Name string `gorm:"column:name"`
		}
		idxQuery := fmt.Sprintf("PRAGMA index_info(%s)", idx.Name)
		if err := app.db.Raw(idxQuery).Scan(&columns).Error; err != nil {
			return false, err
		}

		for _, col := range columns {
			if col.Name == fieldName {
				return true, nil
			}
		}
	}

	return false, nil
}
